/*
 * Copyright 2010 Nicholas Alexander Cross
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.intellij.lang.plist.parser;

import com.intellij.lang.ASTNode;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.PsiParser;
import com.intellij.openapi.util.Key;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;

public class PListParser implements PsiParser {

    private final ArrayParser arrayParser;
    private final DictionaryParser dictionaryParser;

    public PListParser() {
        dictionaryParser = new DictionaryParser();
        arrayParser = new ArrayParser();

        dictionaryParser.setArrayParser( arrayParser );
        arrayParser.setDictionaryParser( dictionaryParser );
    }

    @NotNull
    public ASTNode parse(IElementType root, PsiBuilder builder) {
        final PsiBuilder.Marker rootMarker = builder.mark();

        while (!builder.eof()) {
            parseX(builder);
        }

        final int arrayBraceCount = arrayParser.arrayBraceCount(builder);

        if (arrayBraceCount > 0) {
            builder.error("unclosed array");
        }

        rootMarker.done(root);

        return builder.getTreeBuilt();

    }

    private void parseX(PsiBuilder builder) {
        IElementType tokenType = builder.getTokenType();

        if (tokenType == PListElementTypes.LEFT_BRACE) {

            if (arrayParser.isRootOpened(builder) /*|| dictionaryParser.isRootOpened(builder)*/) {
                builder.error("plists can contain only one root element");
                builder.advanceLexer();
            } else {
                dictionaryParser.setRootOpened(builder, true);
                dictionaryParser.parseDictionary(builder);
            }
        } else if (tokenType == PListElementTypes.LEFT_PARENTHESES ) {
            if (arrayParser.isRootOpened(builder)  /*|| dictionaryParser.isRootOpened(builder)*/) {
                builder.error("plists can contain only one root element");
                builder.advanceLexer();
            } else {
                arrayParser.setRootOpened(builder, true);
                arrayParser.parseArray(builder);
            }
        } else if (tokenType == PListElementTypes.COMMENT) {
            PsiBuilder.Marker marker = builder.mark();
            builder.advanceLexer();
            marker.done(PListElementTypes.COMMENT);
        } else {
            arrayParser.checkForInvalidTokens(builder, tokenType);
            dictionaryParser.checkForInvalidTokens(builder, tokenType);

            if (tokenType != PListElementTypes.RIGHT_BRACE && tokenType != PListElementTypes.RIGHT_PARENTHESES) {
                builder.error( "Invalid plist content" );
            }

            builder.advanceLexer();
        }

    }

}
